#include "precompiled.h"
#include "furywarrior.h"
using namespace std;
using namespace weo::engine::item;
using namespace weo::engine::character::warrior;

Fury::Fury()
{
    Meleedps::Init();
    m_Classnr = weo::engine::character::Character::isAllowed("Warrior");

    m_Basevalues.push_back(Attribute("Agility",93));
    m_Basevalues.push_back(Attribute("Intellect",30));
    m_Basevalues.push_back(Attribute("Strength",148));
    m_Basevalues.push_back(Attribute("Stamina",135));
    m_Basevalues.push_back(Attribute("Spirit",54));
    m_Basevalues.push_back(Attribute("AttackPower",190)); // ap
    m_Basevalues.push_back(Attribute("Health",4364)); // health
    m_Basevalues.push_back(Attribute("CritRating",8*CritRating)); // cr + bersistance
    m_Basevalues.push_back(Attribute("HitRating",3*HitRating)); // precision
    m_Basevalues.push_back(Attribute("ExpertiseRating",4*ExpertiseRating)); // expertiserating
    m_Equip.Mode(0);
    BOOST_FOREACH(Attribute attr, m_Basevalues)
    {
        handleAttribute(attr);
    }
    // base settings finished
}

float Fury::evaluateTF()
{
    float wdps1 = m_Equip[46];
    float wdps2 = m_Equip[48];
    float ws1 = m_Equip[47];
    float ws2 = m_Equip[49];
    float baseap = m_Equip[30];
    float crit = m_Equip[6]/CritRating -0.6f;
    float hit = m_Equip[7]/HitRating;
    float haste = m_Equip[10]/HasteRating;
    bool daggermh = false;
    unsigned int mhtype = m_Equip.getItem(14)->Subtype();
    if(mhtype == 5) 
    {
        daggermh = true;
    }
    float armorreduction = max<float>((MobArmor - m_Equip[50])/(MobArmor - m_Equip[50] + 10557.5f),0);
    // -- glancing blow calculation -- //

    float glancingreduction = 25;
    float glancingprob = 25;
    float glancing = glancingreduction * glancingprob / 100;
    float dodge = 6.5f - (m_Equip[51]/ExpertiseRating) * 0.25f;
    float hitwhite = min<float>(100 - 9 - 19 + hit, 100);
    float hityellow = min<float>(100 - 9 + hit, 100);
    float ap = baseap + 250.0f; // rampage
    float avghit = (hityellow + hitwhite) / 200; // average hit value, already normalized to 0<=x<=1
    float noncrit = (1 - crit / 100); // the chance not to crit
    float flurryvalue = 0.25f;
    // 25% * flurry uptime + possible haste effects, calculating the effective speed
    float flurryprob = (float)min<float>(1 - pow(noncrit, 3.0f + 1 - pow(1 - 0.2f, 3.0f) + ((ws1 + ws2) / 4 / 6)), 1.0f);
    float wsmh = (ws1 / (1 + haste / 100)) * (1 - flurryprob) + (ws1 / ((1 + haste / 100) * (1 + flurryvalue))) * flurryprob;
    float wsoh = (ws2 / (1 + haste / 100)) * (1 - flurryprob) + (ws2 / ((1 + haste / 100) * (1 + flurryvalue))) * flurryprob;
    float avgspeed = (wsmh + wsoh) / 2; // average again for some stuff
    float hastemh = ws1 / wsmh;
    float hasteoh = ws2 / wsoh;
    float nocritinthree = (float) pow(1 - crit/100.0f, 3.0f / avgspeed);
    float bleedcrit = crit * (1 + (1-nocritinthree) * 0.15f); // deep wounds // only assume one tick for now
    float mhwhitedps = (1 / 100.0f) * (hitwhite + bleedcrit - glancing - dodge) * (wdps1 + ap / 14.0f); // normal   mh white swing dps
    float ohwhitedps = 0.625f * (1 / 100.0f) * (hitwhite + bleedcrit - glancing - dodge) * (wdps2 + ap / 14.0f); // normal ohindex swing dps
    float wfdps = 0;
    if(m_Equip.hasSpecial(707723)) // wftotem
    {
        float wfap = ap + 445 * 1.3f;
        wfdps = 1 / 100.0f * 1 / 100.0f * (hitwhite - dodge) * (hitwhite + bleedcrit - dodge) * 0.2f * (wdps1 + wfap / 14); // wf stuff
    }
    float rottime = 18.0f;
    float normaldps = (1.0f-armorreduction) * (hastemh * (mhwhitedps + wfdps) + hasteoh * ohwhitedps); // sum it up put haste as array mult 
    float rageps =  (normaldps*3.75f)/274.7f + ((1/wsmh)*(1+crit/100)*3.5f) + ((1/wsoh)*(1+crit/100)*1.75f) + 1/3.0f - 0.98f; // 0.98f for periodic skills
    float bloodthirstdmg = (hityellow + bleedcrit * 1.2f - dodge) * 1 / 100.0f * (ap * 0.45f);
    if(m_Equip.hasSpecial(946814)) // t6 4p
    {
        bloodthirstdmg *= 1.05f;
    }
    float hsdmg = -(mhwhitedps * ws1 * (1/100.0f) * (hitwhite + bleedcrit - glancing - dodge)) + (wdps1 + ap / 14.0f + 228 / ws1) * ws1 * (hityellow + bleedcrit * 1.2f - dodge) * 1 / 100.0f;
    float instantmult = daggermh ? 1.7f : 2.4f; // instant mult for ww
    float wwdmg = (hityellow + bleedcrit * 1.2f - dodge) * (1 / 100.0f) * ((wdps1*ws1  + instantmult*ap/14)+ (wdps2*ws2 + instantmult*ap/14)*0.625f);
    float hamdmg = (1 / 100.0f) * (hityellow + bleedcrit * 1.2f - dodge) * 63;
    float rotrage = 3*30+2*25+7*10;
    float remainingrage = max<float>(rageps*rottime-rotrage,0.0f);
    float rotdmg = bloodthirstdmg*3 + 2*wwdmg + 6*hamdmg + min<float>((remainingrage/12.0f)*hsdmg, (18/wsmh)*hsdmg); // leaving one hamstring out for other things like rampage
    float finaldps = normaldps + (1.0f-armorreduction) * rotdmg/rottime;
    return m_CondFactor * finaldps;
}
// filtering all those pala tank items
bool filterItemFury(const weo::engine::item::Item* item)
{
    std::vector<weo::engine::item::Attribute>::const_iterator k;
    const std::vector<Attribute> *attrs = item->Attributes();
    bool badattr = false;
    for(k = attrs->begin();k!=attrs->end();k++)
    {
        switch(k->Type())
        {
        case 2:
        case 12:
        case 23:
            badattr = true;
            break;
        default:
            break;
        }
    }
    return badattr;
}
void Fury::filterEquip(std::vector<std::vector<const weo::engine::item::Item*>>& items)
{
    for(unsigned int i = 0;i<10;i++)
    {
        int subtype = 3;
        if(i == 1 || i == 3)
        {
            items.push_back(m_Database->getPtrbyType(1,i+1));
        }
        else
        {	
            items.push_back(m_Database->getPtrbyType(1,i+1,4));
        }
    }
    items.push_back(m_Database->getPtrbyType(2,0));
    items.push_back(m_Database->getPtrbyType(2,0));
    items.push_back(m_Database->getPtrbyType(3,0));
    items.push_back(m_Database->getPtrbyType(3,0));
    // main hand weapons
    vector<const Item*> mainhand;
    for(int i = 1;i<6;i++)
    {
        for(int j = 1;j<3;j++)
        {
            vector<const Item*> weapon = m_Database->getPtrbyType(4,j,i);
            vector<const Item*>::iterator it;
            for(it=weapon.begin();it!=weapon.end();it++)
            {
                mainhand.push_back(*it);
            }
        }
    }
    // off hand weapons
    vector<const Item*> offhand;
    for(int i = 1;i<6;i++)
    {
        for(int j = 1;j<4;j+=2)
        {
            vector<const Item*> weapon = m_Database->getPtrbyType(4,j,i);
            vector<const Item*>::iterator it;
            for(it=weapon.begin();it!=weapon.end();it++)
            {
                offhand.push_back(*it);
            }
        }
    }
    items.push_back(mainhand);
    items.push_back(offhand);
    vector<const Item*> ranged;
    for(int i = 9;i<13;i++)
    {
        vector<const Item*> weapon = m_Database->getPtrbyType(4,5,i);
        vector<const Item*>::iterator it;
        for(it=weapon.begin();it!=weapon.end();it++)
        {
            ranged.push_back(*it);
        }
    }
    items.push_back(ranged); // ranged
    items.push_back(m_Database->getPtrbyType(5,0));
    std::vector<std::vector<const weo::engine::item::Item*>>::iterator it;
    for(it = items.begin();it!= items.end();it++)
    {
        it->erase(std::remove_if(it->begin(), it->end(), filterItemFury),it->end());
    }
    Meleedps::filterEquip(items);
}
void Fury::handleAttribute(const Attribute& attr)
{
    switch(attr.Type())
    {
    case 30:
        Meleedps::handleAttribute(Attribute(attr.Type(),attr.Value()*1.1f)); // ap *1.1f
        break;
    default:
        Meleedps::handleAttribute(attr);
        break;
    }
}